﻿// Copyright (C) Norsolutions GmbH
// All rights reserved.
// For conditions of distribution and use, see license.
// Created by: Reng van Oord
// Created:    2010.05.05


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Resources;
using System.Globalization;
using System.Text;

namespace Sherwood.Localization.Resx
{
    /// <summary>
    /// Provides an implementation of the ITranslationProvider interface which can be used to obtain translations from embedded resource (.resx) files.
    /// </summary>
    public class ResxTranslationProvider : ITranslationProvider
    {
        private ResxTranslationProvider()
        {
        }

        ResourceManager _resourceManager;

        CultureInfo _culture;

        /// <summary>
        /// Instansiates a new instance of an ResxTranslationProvider
        /// </summary>
        /// <param name="resourceSource">Resource type</param>
        /// <param name="cultureName">The .Net culture name for the culture to translate to (e.g. 'en-US').</param>
        public ResxTranslationProvider(Type resourceType, string cultureName)
        {
            _culture = CultureInfo.GetCultureInfo(cultureName);
            _resourceManager = new ResourceManager(resourceType);
        }

        #region ITranslationProvider Members

        /// <summary>
        /// Sets the active translation culture (language)
        /// </summary>
        /// <param name="cultureName">.Net culture name (e.g. 'en-US')</param>
        public void SetCulture(string cultureName)
        {
            _culture = CultureInfo.GetCultureInfo(cultureName);
        }

        /// <summary>
        /// Returns a translation corrosponding to the provided key in the active translation culture.
        /// Translation culture can be changed using the SetCulture() method.
        /// </summary>
        /// <param name="key">Translation key</param>
        /// <returns>Translated string or key if no translation is found</returns>
        public string GetString(string key)
        {
            return GetString(key, key);
        }

        /// <summary>
        /// Returns a translation corrosponding to the provided key in the active translation culture.
        /// Translation culture can be changed using the SetCulture() method.
        /// </summary>
        /// <param name="key">Translation key</param>
        /// <param name="defaultValue">Value to return if no translation is found.</param>
        /// <returns>Translated string or defaultValue if no translation is found</returns>
        public string GetString(string key, string defaultValue)
        {
            key = ConvertToResxKey(key);
            string translation = null;
            try
            {
                translation = _resourceManager.GetString(key, _culture);
            }
            catch (System.Resources.MissingManifestResourceException)
            {
                CultureInfo fallbackCulture = CultureInfo.InvariantCulture;
                if (_culture.Name.Contains("-"))
                {
                    string lessStrictCulture = _culture.Name.Split('-')[0];
                    try
                    {
                        fallbackCulture = CultureInfo.GetCultureInfo(lessStrictCulture);
                    }
                    catch
                    {
                        fallbackCulture = CultureInfo.InvariantCulture;
                    }
                }

                try
                {
                    translation = _resourceManager.GetString(key, fallbackCulture);
                }
                catch (System.Resources.MissingManifestResourceException)
                {
                    fallbackCulture = CultureInfo.InvariantCulture;

                    try
                    {
                        translation = _resourceManager.GetString(key, fallbackCulture);
                    }
                    catch (System.Resources.MissingManifestResourceException)
                    {
                        translation = defaultValue;
                    }
                }
            }
            if (translation == null || translation == "")
            {
                return defaultValue;
            }
            return translation;
        }

        /// <summary>
        /// Returns a translation corrosponding to the provided key in the active translation culture.
        /// Translation culture can be changed using the SetCulture() method.
        /// </summary>
        /// <param name="key">Translation key</param>
        /// <param name="defaultValue">The value to be returned if no translation is found.</param>
        /// <param name="callback">The function to call once translation has been obtained</param>
        public void GetStringAsync(string key, string defaultValue, TranslationCallback callback, object state)
        {
            string translation = GetString(key, defaultValue);
            callback(key, translation, state);
        }

        /// <summary>
        /// Returns a translation corrosponding to the provided key in the active translation culture.
        /// Translation culture can be changed using the SetCulture() method.
        /// </summary>
        /// <param name="key">Translation key</param>
        /// <returns>Translated string or key if no translation is found</returns>
        public string this[string key]
        {
            get { return GetString(key); }
        }

        #endregion

        /// <summary>
        /// Converts a string to a format that would make it suitable as a .Net resx file key
        /// </summary>
        /// <param name="lookup">Original key string</param>
        /// <returns></returns>
        protected string ConvertToResxKey(string lookup)
        {
            StringBuilder returnValue = new StringBuilder();
            string allowedCharacters = "abcdefghijklmnopqrstuvwxyzåøæABCDEFGHIJKLMNOPQRSTUVWXYZÅÆØ1234567890_-";
            string numbers = "1234567890";
            lookup = lookup.Replace(" ", "_");
            if (lookup != null)
            {
                //Remove non-allowed characters from string
                for (int i = 0; i < lookup.Length; i++)
                {
                    for (int j = 0; j < allowedCharacters.Length; j++)
                    {
                        if (lookup[i] == allowedCharacters[j])
                        {
                            returnValue.Append(lookup[i]);
                            break;
                        }
                    }
                }

                //Remove numbers from start of string
                while (returnValue.Length > 0 && numbers.Contains(returnValue[0]))
                {
                    returnValue.Remove(0, 1);
                }
            }
            return returnValue.ToString().Trim();
        }
    }
}
